package com.karaku.karaku_collector.common.binder;

import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.karaku.karaku_collector.App;
import com.karaku.karaku_collector.common.KarakuActivityManager;
import com.karaku.karaku_collector.util.ClassUtil;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * Created by guoping on 15/12/7.
 */
public class UIBinder {

    public static View bind(Object obj) {
        View v = getViewWithObj(obj);
        bind(obj, v);
        return v;
    }

    public static View bind(Object obj, Context context) {
        View v = getViewWithObj(obj, context);
        bind(obj, v);
        return v;
    }

    public static View bind(Object obj, ViewGroup viewGroup, boolean attach) {
        Class containerClass = obj.getClass();
        BindView bv = getAnnotation(BindView.class, containerClass.getDeclaredAnnotations());
        if (bv == null) {
            return null;
        }
        View view = LayoutInflater.from(App.getInstance()).inflate(bv.value(), viewGroup, attach);
        initViews(obj, view);
        bindOnClick(obj, view);
        return view;
    }

    public static void bind(Object obj, View view) {
        initViews(obj, view);
        bindOnClick(obj, view);
    }

    private static View getViewWithObj(Object obj) {
        Context context = getContext(obj);
        return getViewWithObj(obj, context);
    }

    private static View getViewWithObj(Object obj, Context context) {
        Integer layoutId = getLayoutId(obj);
        if (layoutId != null) {
            ViewGroup parent = (obj instanceof ViewGroup) ? ((ViewGroup) obj) : null;
            if (parent == null) {
                return LayoutInflater.from(context).inflate(layoutId, null);
            } else {
                return LayoutInflater.from(context).inflate(layoutId, parent, true);
            }
        }
        return getView(obj);
    }

    private static Context getContext(Object obj) {
        if (obj instanceof View) {
            return ((View) obj).getContext();
        } else if (obj instanceof Activity) {
            return (Activity) obj;
        } else if (obj instanceof Dialog) {
            return ((Dialog) obj).getContext();
        } else {
            return KarakuActivityManager.lastOrDefault();
        }
    }

    private static View getView(Object obj) {
        if (obj instanceof View) {
            return (View) obj;
        } else if (obj instanceof Activity) {
            return ((Activity) obj).getWindow().getDecorView();
        } else if (obj instanceof Dialog) {
            return ((Dialog) obj).getWindow().getDecorView();
        }
        return null;
    }

    private static Integer getLayoutId(Object obj) {
        Class containerClass = obj.getClass();
        BindView bv = (BindView) containerClass.getAnnotation(BindView.class);
        if (bv == null) {
            return null;
        }
        return bv.value();
    }

    private static void initViews(Object obj, View view) {
        try {
            Field[] fields = obj.getClass().getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                BindView vm = getAnnotation(BindView.class, field.getDeclaredAnnotations());
                if (vm != null) {
                    field.set(obj, view.findViewById(vm.value()));
                }
            }
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }

    private static void bindOnClick(final Object obj, View view) {
        try {
            Method[] ms = obj.getClass().getDeclaredMethods();
            for (final Method m : ms) {
                m.setAccessible(true);
                OnClick oc = getAnnotation(OnClick.class, m.getDeclaredAnnotations());
                if (oc != null) {
                    for (int id : oc.value()) {
                        View v = view.findViewById(id);
                        if (v != null) {
                            v.setOnClickListener(new View.OnClickListener() {
                                @Override
                                public void onClick(View v) {
                                    try {
                                        if (m.getParameterTypes().length == 0) {
                                            m.invoke(obj);
                                        } else {
                                            m.invoke(obj, v);
                                        }
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                    }
                                }
                            });
                        }
                    }
                }
            }
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }

    private static <T> T getAnnotation(Class<? extends T> classOfT, Annotation[] as) {
        T r = null;
        for (Annotation a : as) {
            if (ClassUtil.isSubClass(a.getClass(), classOfT)) {
                r = (T) a;
            }
        }
        return r;
    }
}
